namespace FIREFLYX {
    // export interface IAsset {
    //     /** 获取资源ID */
    //     ID: number;
    //     /** 获取资源名 */
    //     name: string;
    //     /** 是否被销毁 */
    //     isDisposed: boolean;
    // }

    /** 资源处理器接口 */
    export interface IAssetProcessor {
        /** 资源类型 */
        Type: AssetType;
        /** 文件识别后缀 */
        suffix: string;
        /** 文件加载数据类型 */
        rawType: XMLHttpRequestResponseType;
        /**
         * 解析资源
         * @param data 资源数据
         * @param filePath 资源文件路径
         */
        parse(data: any, filePath?: string): Nullable<Asset>;
    }

    /** 资源类型 */
    export enum AssetType {
        ERROR,
        BIN,
        MESH,
        OBJ_MESH,
        TEXTURE,
        HTML_IMAGE,
        PREFAB,
        GLTF,
        GLB,
        ASSET_BUNDLE,
        GLSL,
        SHADER,
        MATERIAL
    }

    /** 资源解析时传递参数Map */
    // eslint-disable-next-line @typescript-eslint/naming-convention
    export const ResPathProcessorParameterMap: Map<string, object> = new Map();

    /** 资源管理器 */
    export class AssetManager {
        //资源加载完毕的缓存Map
        private static readonly CacheResMap: { [key: string]: Asset } = {};
        //加载中的资源Map
        private static readonly LoadingResMap: { [key: string]: boolean } = {};
        //匹配后缀
        private static readonly SuffixPattern: RegExp = /(\.([a-z|0-9]*)){1,2}$/;
        private static ParserMap: { [key: number]: IAssetProcessor } = {};
        private static SuffixMap: { [key: string]: AssetType } = {};

        public static init() {
            //proccessor 注册
            this.RegProcessor(new HtmlImageProcessor());
            this.RegProcessor(new PngTexProcessor());
            this.RegProcessor(new JpgTexProcessor());
            this.RegProcessor(new WebpTexProcessor());
            this.RegProcessor(new OBJMeshProcessor());
            this.RegProcessor(new BinProcessor());
            this.RegProcessor(new GLTFProcessor());
            this.RegProcessor(new GLBProcessor());
            this.RegProcessor(new ShaderProcessor());
            this.RegProcessor(new GLSLProcessor());
        }

        /**
         * 获取文件的引擎资源类型
         * @param path 文件资源路径
         * @returns 引擎资源类型
         */
        public static GetFileType(path: string): AssetType {
            let temp = this.SuffixPattern.exec(path);
            if (!temp || temp.length < 0) return AssetType.ERROR;
            let fullSuffix = temp[0];                                       //可能是 双后缀(.xx) 或 单后缀(.xx.yy)
            let lastSuffix: string = fullSuffix;                            //单后缀(.xx.yy)
            let result = this.SuffixMap[fullSuffix];
            //.xx.*  使用* 模式的 双后缀
            if (result == null && temp.length > 1) {
                lastSuffix = temp[1];
                let startSuffix = fullSuffix.replace(lastSuffix, `.*`);
                result = this.SuffixMap[startSuffix];
            }

            //双后缀 没匹配到，尝试取 单后缀
            if (result == null && lastSuffix) {
                result = this.SuffixMap[lastSuffix];
            }

            //最后也没找到 标记为 error
            if (result == null) return AssetType.ERROR;
            return result;
        }

        /**
         * 异步加载单文件资源通过路径
         * @param path 文件路径
         * @returns 资源
         */
        public static async LoadFile(path: string): Promise<Nullable<Asset>> {
            //注：加载开多线，加载完排入队列，逐个解析
            //先找缓存看是否存在
            if (this.CacheResMap[path]) { return this.CacheResMap[path]; }
            let fType = this.GetFileType(path);
            if (fType == AssetType.ERROR) {
                //文件类型不支持
                console.error(`file :${path} , type not supported!`);
                return null;
            }

            //加载中处理
            if (this.CacheResMap[path]) {
                let _wait2Loaded = new Promise<Nullable<Asset>>((res, rej) => {
                    let obj = {
                        loaded: () => { res(this.CacheResMap[path]); },
                        loadFail: () => { rej(new Error(`file loadFail of path : ${path}`)); },
                        unReg: () => {
                            GlobalEventManager.Instance.removeListener("assetLoaded", obj.loaded, obj);
                            GlobalEventManager.Instance.removeListener("assetLoadFail", obj.loadFail, obj);
                        },
                    };
                    GlobalEventManager.Instance.addListener("assetLoaded", obj.loaded, obj);
                    GlobalEventManager.Instance.addListener("assetLoadFail", obj.loadFail, obj);
                });
                //返回 等候结果的 Promise
                return _wait2Loaded;
            }

            //文件名
            let fileName = GetFileName(path);

            //加载文件资源数据
            let proccessor = this.ParserMap[fType];
            this.LoadingResMap[path] = true;
            let data = await FileLoad.xhr(path, proccessor.rawType);
            //是image类型等待image的load结束
            if (proccessor.rawType == "blob" && (data.type as string).substring(0, 5) == "image") {
                // let imgP = new Promise<HTMLImageElement>((res, rej) => {
                //     let img = new Image();
                //     img.src = window.URL.createObjectURL(data);
                //     img.onload = () => { res(img); };
                //     img.onerror = (err) => { rej(err); };
                // });
                let imgP = FileLoad.loadImage(window.URL.createObjectURL(data));
                data = await imgP;
            }
            //根据文件后缀判定资源类型
            //解析资源
            let asset = this.ParseRaw(data, fType, path);
            //清理加载中标记
            delete this.LoadingResMap[path];
            if (asset) {
                asset.name = fileName;
                //资源对象不为空，成功
                this.CacheResMap[path] = asset;
                //event dispath
                if (GlobalEventManager.Instance.listenerCount("assetLoaded") > 0) { GlobalEventManager.Instance.dispatchEvent("assetLoaded", path); }
            } else {
                //event dispath
                if (GlobalEventManager.Instance.listenerCount("assetLoadFail") > 0) { GlobalEventManager.Instance.dispatchEvent("assetLoadFail", path); }
            }
            return asset;
        }

        /**
         * 解析资源
         * @param data 资源数据
         * @param fType 资源类型
         * @param filePath 资源文件路径
         * @returns 资源
         */
        public static ParseRaw(data: any, fType: AssetType, filePath: string): Nullable<Asset> {
            let proccessor = this.ParserMap[fType];
            let asset = proccessor.parse(data, filePath);
            return asset;
        }

        /**
         * 获取已缓存资源
         * @param resKey 文件路径、标识字符串
         */
        public static GetAsset(resKey: string): Asset {
            return this.CacheResMap[resKey];
        }

        /**
         * 添加设置资源
         * @param resKey 资源名(文件路径、标识字符串)
         * @param res 资源对象(为空表示从容器移除)
         */
        public static SetAsset(resKey: string, res: Nullable<Asset>) {
            if (!resKey) return;
            if (res) {
                this.CacheResMap[resKey] = res;
            } else {
                delete this.CacheResMap[resKey];
            }
        }

        /**
         * 注册资源处理器
         * @param processor 资源处理器
         */
        public static RegProcessor(processor: IAssetProcessor) {
            this.ParserMap[processor.Type] = processor;
            this.SuffixMap[processor.suffix] = processor.Type;
        }
    }
}